<?php
// +----------------------------------------------------------------------
// | Created by PHPstorm: JRKAdmin框架 [ JRKAdmin ]
// +----------------------------------------------------------------------
// | Copyright (c) 2019~2022 [LuckyHHY] All rights reserved.
// +----------------------------------------------------------------------
// | SiteUrl: http://www.luckyhhy.cn
// +----------------------------------------------------------------------
// | Author: LuckyHhy <jackhhy520@qq.com>
// +----------------------------------------------------------------------
// | Date: 2020/3/18-10:12
// +----------------------------------------------------------------------
// | Description:
// +----------------------------------------------------------------------


namespace app\addons\controller;


use app\addons\model\Addons as Addons_Model;
use app\addons\validate\Hooks;
use app\common\controller\BaseController;
use Jrk\File;
use Jrk\PclZip;
use think\Db;
use think\Exception;
use think\facade\App;
use think\facade\Cache;
use think\facade\Request;


class Addons extends BaseController
{

    /**
     * @return bool|mixed
     * @author: LuckyHhy <jackhhy520@qq.com>
     * @date: 2020/3/18 0018
     * @name: index
     * @describe:
     */
    public function index()
    {
        if (IS_AJAX) {
            //取得模块目录名称
            $dirs = array_map('basename', glob(ADDON_PATH . '*', GLOB_ONLYDIR));
            if ($dirs === false || !file_exists(ADDON_PATH)) {
                $this->ajaxResult([], 100, '插件目录不可读或者不存在', 0);
                return false;
            }
            // 读取数据库插件表
            $addons = Addons_Model::order('id desc')->column(true, 'name');
            //遍历插件列表
            foreach ($dirs as $value) {
                //是否已经安装过
                if (!isset($addons[$value])) {
                    $class = get_addon_class($value);
                    if (!class_exists($class)) {
                        // 实例化插件失败忽略执行
                        $addons[$value]['uninstall'] = -1;
                        continue;
                    }
                    //获取插件配置
                    $obj = new $class();
                    $addons[$value] = $obj->info;
                    if ($addons[$value]) {
                        $addons[$value]['uninstall'] = 1;
                        unset($addons[$value]['status']);

                    }
                }
            }
            int_to_string($addons, array('status' => array(-1 => '损坏', 0 => '禁用', 1 => '启用', null => '未安装')));
            $this->ajaxResult($addons, 0, 'ok', count($addons));
        }

        return $this->fetch();
    }


    /**
     * @return mixed|\think\response\Json
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     * @author: LuckyHhy <jackhhy520@qq.com>
     * @date: 2020/3/18 0018
     * @name: hooks
     * @describe:插件钩子列表
     */
    public function hooks()
    {
        if(IS_AJAX){
           return App::model("Hooks")->getAdminPageData(Request::param());
        }
        return $this->fetch();
    }


    /**\
     * @return mixed
     * @author: LuckyHhy <jackhhy520@qq.com>
     * @date: 2020/3/21 0021
     * @name: hookDel
     * @describe:删除钩子
     */
    public function hookDel(){
        if (IS_AJAX){
            $ids = $this->request->post("ids");
            return App::model("Hooks")->del($ids);
        }
    }


    /**
     * @return mixed
     * @author: LuckyHhy <jackhhy520@qq.com>
     * @date: 2020/3/21 0021
     * @name: hookOk
     * @describe:启用钩子
     */
    public function hookOk(){
        if (IS_AJAX){
            $ids = $this->request->post("ids");
            return App::model("Hooks")->isOkOrFalse($ids,1);
        }
    }


    /**、
     * @return mixed
     * @author: LuckyHhy <jackhhy520@qq.com>
     * @date: 2020/3/21 0021
     * @name: hookFalse
     * @describe:禁用钩子
     */
    public function hookFalse(){
        if (IS_AJAX){
            $ids = $this->request->post("ids");
            return App::model("Hooks")->isOkOrFalse($ids);
        }
    }


    /**
     * @return mixed
     * @author: LuckyHhy <jackhhy520@qq.com>
     * @date: 2020/3/21 0021
     * @name: addHook
     * @describe:添加
     */
    public function addHook(){
        if (IS_POST){
            $data=Request::post();
            $validate=new Hooks();
            if (!$validate->check($data)){
                $this->error($validate->getError());
            }
            if (isset($data['id'])) {

            } else {

            }
            return App::model("Hooks")->addAndEdit($data);
        }
        $addons=Addons_Model::select();
        $this->assign("addons",$addons);
        $this->assign("info",[]);
        return $this->fetch();
    }


    /**
     * @return mixed
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     * @author: LuckyHhy <jackhhy520@qq.com>
     * @date: 2020/3/21 0021
     * @name: editHook
     * @describe:编辑
     */
    public function editHook(){
        $id=Request::param("id/d");
        $info=App::model("Hooks")->where("id",$id)->find();
        if (!$info){
            $this->error("id 错误");
        }
        $addons=Addons_Model::select();
        $this->assign("addons",$addons);
        $this->assign("info",$info);
        return $this->fetch("add_hook");
    }

    /***
     * @return mixed
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     * @author: LuckyHhy <jackhhy520@qq.com>
     * @date: 2020/3/18 0018
     * @name: config
     * @describe:设置插件页面
     */
    public function config()
    {
        $addonId = $this->request->param('id/d');
        if (empty($addonId)) {
            $this->error('请选择需要操作的插件！');
        }
        //获取插件信息
        $addon = Addons_Model::where(array('id' => $addonId))->find();
        if (!$addon) {
            $this->error('该插件没有安装！');
        }
        $addon = $addon->toArray();
        //实例化插件入口类
        $addon_class = get_addon_class($addon['name']);
        if (!class_exists($addon_class)) {
            trace("插件{$addon['name']}无法实例化,", 'ADDONS', 'ERR');
        }
        $addonObj = new $addon_class();
        $addon['addon_path'] = $addonObj->addon_path;
        $addon['custom_config'] = isset($addonObj->custom_config) ? $addonObj->custom_config : '';
        $db_config = $addon['config'];
        //载入插件配置数组
        $addon['config'] = include $addonObj->config_file;
        if ($db_config) {
            $db_config = json_decode($db_config, true);
            foreach ($addon['config'] as $key => $value) {
                if ($value['type'] != 'group') {
                    $addon['config'][$key]['value'] = isset($db_config[$key]) ? $db_config[$key] : '';
                } else {
                    foreach ($value['options'] as $gourp => $options) {
                        foreach ($options['options'] as $gkey => $value) {
                            $addon['config'][$key]['options'][$gourp]['options'][$gkey]['value'] = $db_config[$gkey];
                        }
                    }
                }
            }
        }
        $this->assign('data', $addon);
        if ($addon['custom_config']) {
            //加载配置文件config.html
            $this->assign('custom_config', $this->view->fetch($addon['addon_path'] . $addon['custom_config']));
        }
        return $this->fetch();
    }

    /**
     * @author: LuckyHhy <jackhhy520@qq.com>
     * @date: 2020/3/18 0018
     * @name: saveConfig
     * @describe:保存插件设置
     */
    public function saveConfig()
    {
        if (IS_POST) {
            $id = $this->request->post('id/d');
            try {
                //获取插件信息
                $info = Addons_Model::where(array('id' => $id))->find();
                if (empty($info)) {
                    $this->error('该插件没有安装！');
                }
                $config = $this->request->post('config/a');
                $flag = Db::name('Addons')->where(['id' => $id])->setField('config', json_encode($config));
                if ($flag !== false) {
                    $this->success('保存成功');
                } else {
                    $this->error('保存失败');
                }
            } catch (Exception $exception) {
                $this->error($exception->getMessage());
            }
        }
    }

    /**
     * @throws Exception
     * @throws \think\exception\PDOException
     * @author: LuckyHhy <jackhhy520@qq.com>
     * @date: 2020/3/18 0018
     * @name: enable
     * @describe:启用插件
     */
    public function enable()
    {
        if (IS_POST) {
            $id = $this->request->param('id/d');
            $res = Addons_Model::where('id', $id)->update(['status' => 0]);
            if ($res) {
                $this->success('启用成功');
            } else {
                $this->error('启用失败');
            }
        }
    }

    /**
     * @throws Exception
     * @throws \think\exception\PDOException
     * @author: LuckyHhy <jackhhy520@qq.com>
     * @date: 2020/3/18 0018
     * @name: disable
     * @describe:禁用插件
     */
    public function disable()
    {
        if (IS_POST) {
            $id = $this->request->param('id/d');
            $res = Addons_Model::where('id', $id)->update(['status' => 0]);
            if ($res) {
                $this->success('禁用成功');
            } else {
                $this->error('禁用失败');
            }
        }
    }

    /***
     * @throws \think\Exception
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     * @throws \think\exception\PDOException
     * @author: LuckyHhy <jackhhy520@qq.com>
     * @date: 2020/3/18 0018
     * @name: install
     * @describe:安装插件
     */
    public function install()
    {
        $addonName = $this->request->param('addon_name');
        if (empty($addonName)) {
            $this->error('请选择需要安装的插件！');
        }
        //检查插件是否安装
        if ($this->isInstall($addonName)) {
            $this->error('该插件已经安装，无需重复安装！');
        }
        $class = get_addon_class($addonName);
        if (!class_exists($class)) {
            $this->error('获取插件对象出错！');
        }
        $addonObj = new $class();
        //获取插件信息
        $info = $addonObj->info;
        if (empty($info)) {
            $this->error('插件信息获取失败！');
        }

        try {
            //开始安装
            $install = $addonObj->install();
            if ($install !== true) {
                if (method_exists($addonObj, 'getError')) {
                    $this->error($addonObj->getError() ?: '执行插件预安装操作失败！');
                } else {
                    $this->error('执行插件预安装操作失败！');
                }
            }
            $info['config'] = json_encode($addonObj->getAddonConfig());

            //添加插件安装记录
            $res = Addons_Model::create($info, true);
            if (!$res) {
                $this->error('写入插件数据失败！');
            }
            // 复制静态资源
            $sourceAssetsDir = self::getSourceAssetsDir($addonName);
            $destAssetsDir = self::getDestAssetsDir($addonName);
            if (is_dir($sourceAssetsDir)) {
                File::copy_dir($sourceAssetsDir, $destAssetsDir);
            }
            //如果插件有自己的后台
            /*  if (isset($info['has_adminlist']) && $info['has_adminlist']) {
                  $admin_list = $addonObj->admin_list;
                  //添加菜单
                  model('admin/Menu')->addAddonMenu($info, $admin_list);
              }*/
            //更新插件行为实现
            $hooks_update = model('admin/Hooks')->updateHooks($addonName);

            if (!$hooks_update) {
                $this->where("name='{$addonName}'")->delete();
                $this->error('更新钩子处插件失败,请卸载后尝试重新安装！');
            }
            addLog("插件操作", "插件安装成功！{$addonName}");

            Cache::set('Hooks', null);
        } catch (Exception $exception) {
            $this->error($exception->getMessage());
        }

        $this->success('插件安装成功！清除浏览器缓存和框架缓存后生效！');
    }

    /**
     * @throws \think\Exception
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     * @throws \think\exception\PDOException
     * @author: LuckyHhy <jackhhy520@qq.com>
     * @date: 2020/3/18 0018
     * @name: uninstall
     * @describe:卸载插件
     */
    public function uninstall()
    {
        $addonId = $this->request->param('id/d');
        if (empty($addonId)) {
            $this->error('请选择需要卸载的插件！');
        }
        //获取插件信息
        $info = Addons_Model::where(array('id' => $addonId))->find();
        $class = get_addon_class($info['name']);
        if (empty($info) || !class_exists($class)) {
            $this->error('该插件不存在！');
        }
        //插件标识
        $addonName = $info['name'];
        //检查插件是否安装
        if ($this->isInstall($addonName) == false) {
            $this->error('该插件未安装，无需卸载！');
        }
        try {

            //卸载插件
            $addonObj = new $class();
            $uninstall = $addonObj->uninstall();
            if ($uninstall !== true) {
                if (method_exists($addonObj, 'getError')) {
                    $this->error($addonObj->getError() ? $addonObj->getError() : '执行插件预卸载操作失败！');
                } else {
                    $this->error('执行插件预卸载操作失败！');
                }
            }
            if (false !== Addons_Model::destroy($addonId)) {
                //删除插件后台菜单
                /*  if (isset($info['has_adminlist']) && $info['has_adminlist']) {
                      model('admin/Menu')->delAddonMenu($info);
                  }*/
                // 移除插件基础资源目录
                $destAssetsDir = self::getDestAssetsDir($addonName);
                if (is_dir($destAssetsDir)) {
                    File::del_dir($destAssetsDir);
                }
                $hooks_update = model('admin/Hooks')->removeHooks($addonName);
                if ($hooks_update === false) {
                    $this->error('卸载插件所挂载的钩子数据失败！');
                }
                Cache::set('Hooks', null);
                addLog("插件操作", "卸载插件{$addonName}");

                $this->success('插件卸载成功！清除浏览器缓存和框架缓存后生效！');
            } else {
                $this->error('插件卸载失败！');
            }
        } catch (Exception $exception) {
            $this->error($exception->getMessage());
        }
    }

    /**
     * @author: LuckyHhy <jackhhy520@qq.com>
     * @date: 2020/3/18
     * @name: local
     * @describe:本地安装插件
     */
    public function local()
    {
        if ($this->request->isPost()) {
            $files = $this->request->file('file');
            if ($files == null) {
                $this->error("请选择上传文件！");
            }
            if (strtolower(substr($files->getInfo('name'), -3, 3)) != 'zip') {
                $this->error("上传的文件格式有误！");
            }
            //插件名称
            $addonName = pathinfo($files->getInfo('name'));
            $addonName = $addonName['filename'];
            //检查插件目录是否存在
            if (file_exists(ADDON_PATH . $addonName)) {
                $this->error('该插件目录已经存在！');
            }
            //上传临时文件地址
            $filename = $files->getInfo('tmp_name');

            $zip = new PclZip($filename);

            $status = $zip->extract(PCLZIP_OPT_PATH, ADDON_PATH . $addonName);
            if ($status) {
                $this->success('插件解压成功，可以进入插件管理进行安装！', url('index'));
            } else {
                $this->error('插件解压失败！');
            }
        }
    }


    /**
     * @param $name
     * @return bool
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     * @author: LuckyHhy <jackhhy520@qq.com>
     * @date: 2020/3/18
     * @name: isInstall
     * @describe:检查插件是否已经安装
     */
    public function isInstall($name)
    {
        if (empty($name)) {
            return false;
        }
        $count = Addons_Model::where(array('name' => $name))->find();
        return $count ? true : false;
    }


    /**
     * @param $name
     * @return string
     * @author: LuckyHhy <jackhhy520@qq.com>
     * @date: 2020/3/18
     * @name: getSourceAssetsDir
     * @describe:获取插件源资源文件夹
     */
    protected static function getSourceAssetsDir($name)
    {
        return ADDON_PATH . $name . DIRECTORY_SEPARATOR . 'public' . DIRECTORY_SEPARATOR;
    }


    /**
     * @param $name
     * @return string
     * @author: LuckyHhy <jackhhy520@qq.com>
     * @date: 2020/3/18
     * @name: getDestAssetsDir
     * @describe:获取插件目标资源文件夹
     */
    protected static function getDestAssetsDir($name)
    {
        $assetsDir = ROOT_PATH . str_replace("/", DIRECTORY_SEPARATOR, "public/static/addons/{$name}/");
        if (!is_dir($assetsDir)) {
            mkdir($assetsDir, 0755, true);
        }
        return $assetsDir;
    }


}